package com.naiterui.ehp.bs.cms.modules.agent.service.impl;

import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import com.naiterui.ehp.bp.utils.lang.ConfigUtil;
import com.naiterui.ehp.bp.utils.notice.AppNoticeUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.naiterui.ehp.bp.support.exception.BusinessException;
import com.naiterui.ehp.bs.cms.common.exception.BusinessExceptionCode;
import com.naiterui.ehp.bs.cms.common.vo.PageParamsVO;
import com.naiterui.ehp.bs.cms.common.vo.PageVO;
import com.naiterui.ehp.bs.cms.modules.agent.entity.AgAgent;
import com.naiterui.ehp.bs.cms.modules.agent.entity.AgAgentArea;
import com.naiterui.ehp.bs.cms.modules.agent.entity.AgArea;
import com.naiterui.ehp.bs.cms.modules.agent.mapper.AgAgentAreaMapper;
import com.naiterui.ehp.bs.cms.modules.agent.mapper.AgAgentMapper;
import com.naiterui.ehp.bs.cms.modules.agent.mapper.AgAreaMapper;
import com.naiterui.ehp.bs.cms.modules.agent.po.AreaPagePO;
import com.naiterui.ehp.bs.cms.modules.agent.po.AreaSavePO;
import com.naiterui.ehp.bs.cms.modules.agent.service.IAgentAreaService;
import com.naiterui.ehp.bs.cms.modules.agent.vo.AreaDetailVO;
import com.naiterui.ehp.bs.cms.modules.agent.vo.AreaItemVO;
import com.naiterui.ehp.bs.cms.modules.agent.vo.IdAndName;
import com.naiterui.ehp.bs.cms.modules.agent.vo.TreeDataVO;

import cn.hutool.core.util.NumberUtil;

/**
 * @author yiren
 * @since 2022/2/16
 */
@Slf4j
@Service
public class AgentAreaServiceImpl extends ServiceImpl<AgAreaMapper, AgArea> implements IAgentAreaService {

	@Autowired
	private AgAgentAreaMapper agAgentAreaMapper;
	@Autowired
	private AgAgentMapper agAgentMapper;

	@Override
	public PageVO<AreaItemVO> queryPage(PageParamsVO pageParamsVO, AreaPagePO pagePO, Integer areaLev) {
		QueryWrapper<AreaPagePO> entityWrapper = this.buildEntityWrapper(pageParamsVO, pagePO);
		entityWrapper.eq("t.area_lev", areaLev);
		IPage<AreaItemVO> page = this.baseMapper.getPage(pageParamsVO.getPage(), entityWrapper);
		List<AreaItemVO> dataList = page.getRecords();
		if (dataList.size() > 0) {
			List<Long> idList = new ArrayList<>();
			Map<Long, List<IdAndName>> dataMap = new HashMap<>();
			for (AreaItemVO item : dataList){
				idList.add(item.getId());
				item.setChildCity(new ArrayList<>());
				dataMap.put(item.getId(), item.getChildCity());
			}
			List<AgArea> dbAreaList = this.lambdaQuery().in(AgArea::getParentId, idList).list();
			for (AgArea item : dbAreaList) {
				dataMap.get(item.getParentId()).add(IdAndName.of(item.getId(), item.getAreaName()));
			}
		}
		return PageVO.toPageVo(page);
	}

	@Override
	public AreaDetailVO getDetail(Long id) {
		AreaDetailVO detailVO = new AreaDetailVO();

		AgArea dbArea = this.baseMapper.selectById(id);
		detailVO.setId(dbArea.getId());
		detailVO.setAreaName(dbArea.getAreaName());

		List<AgAgentArea> dbAgentAreaList = agAgentAreaMapper.selectList(
				Wrappers.lambdaQuery(AgAgentArea.class)
						.eq(AgAgentArea::getAreaId, dbArea.getId())
						.eq(AgAgentArea::getTitleType, AgAgentArea.TITLE_TYPE_MANAGE));

		if (dbAgentAreaList != null && dbAgentAreaList.size() > 0){
			AgAgentArea dbAgentArea = dbAgentAreaList.get(0);
            if (dbAgentArea != null && dbAgentArea.getAgentId() != null) {
                AgAgent dbAgent = agAgentMapper.selectById(dbAgentArea.getAgentId());
                detailVO.setAgentId(dbAgent.getId());
                detailVO.setAgentName(dbAgent.getName());
                detailVO.setCardNo(dbAgent.getCardNo());
                detailVO.setAgentPhone(dbAgent.getPhone());
            }
		}

		List<AgArea> childList = this.lambdaQuery().eq(AgArea::getParentId, dbArea.getId()).list();
		List<IdAndName> childCity = childList.stream().map(agArea -> {
			IdAndName idAndName = new IdAndName();
			idAndName.setId(agArea.getId());
			idAndName.setName(agArea.getAreaName());
			return idAndName;
		}).collect(Collectors.toList());
		detailVO.setChildCity(childCity);
		return detailVO;
	}

	@Override
	public List<TreeDataVO> findTreeData(Integer type) {
		List<AgArea> dbList = this.lambdaQuery().list();
		// 最终返回的数据
		List<TreeDataVO> resultList = new ArrayList<>();
		Map<Long, TreeDataVO> responseMap = new HashMap<>();
		for (AgArea source : dbList) {
			TreeDataVO response = TreeDataVO.of(source.getId(), source.getAreaName());
			responseMap.put(response.getId(), response);
			if (source.getParentId() != null && source.getParentId() == 0){
				// 顶级
				resultList.add(response);
			}
		}

		for (AgArea source : dbList) {
			if (source.getParentId()==null){
				continue;
			}
			TreeDataVO parentResponse = responseMap.get(source.getParentId());
			if (parentResponse != null) {
				if(parentResponse.getChild()==null){
					parentResponse.setChild(new ArrayList<>());
				}
				parentResponse.getChild().add(responseMap.get(source.getId()));
			}
		}
		if (type != null && type == 2) {
			resultList = resultList.stream().filter(a -> a.getChild() != null && a.getChild().size() > 0).collect(Collectors.toList());
		}
		return resultList;
	}

	@Override
	public void saveArea(AreaSavePO savePO, Integer areaLev) throws BusinessException {

		if (savePO.getAgentId() != null) {
			AgAgent dbAgent = agAgentMapper.selectById(savePO.getAgentId());
			if (dbAgent == null) {
				throw new BusinessException(BusinessExceptionCode.PARAM_ERROR, "经纪人ID不存在");
			}
		}
		AgArea dbArea = null;
		if (savePO.getId() == null) {
			// 检查区域名称是否存在
			checkAreaNameInDB(savePO.getAreaName(), areaLev);
			dbArea = new AgArea();
			dbArea.setAreaLev(areaLev);
			dbArea.setStatus(1);
			dbArea.setParentId(0L);
		}else{
			dbArea = this.baseMapper.selectById(savePO.getId());
			if (dbArea == null) {
				throw new BusinessException(BusinessExceptionCode.PARAM_ERROR, "区域ID不存在");
			}
			if (!savePO.getAreaName().equals(dbArea.getAreaName())){
				checkAreaNameInDB(savePO.getAreaName(), areaLev);
			}
		}
		dbArea.setAreaName(savePO.getAreaName());
		this.saveOrUpdate(dbArea);
		if (areaLev == AgArea.AREA_LEV_REGION) {
			if (savePO.getCityIds() != null && savePO.getCityIds().size() > 0) {
				List<AgArea> dbAgAreaList = this.lambdaQuery().eq(AgArea::getParentId, dbArea.getId()).list();
				List<Long> deleteIdList = new ArrayList<>();
				for (AgArea item : dbAgAreaList) {
					if (!savePO.getCityIds().contains(item.getId())){
						deleteIdList.add(item.getId());
					}
				}
				// 取消绑定的省区：parentId字段改为null，允许大区重新绑定
				updateAgAreaParentId(deleteIdList, null);
				// 绑定的省区：parentId字段改为对应大区的ID，不允许其它大区再次绑定
				updateAgAreaParentId(savePO.getCityIds(), dbArea.getId());
			}
		}
		areaBindAgent(dbArea, savePO.getAgentId());
	}

	private void checkAreaNameInDB(String areaName, Integer areaLev) throws BusinessException {
		long haveRow = this.lambdaQuery().eq(AgArea::getAreaLev, areaLev).eq(AgArea::getAreaName, areaName).count();
		if (haveRow > 0) {
			throw new BusinessException(BusinessExceptionCode.PARAM_ERROR, "区域名称已存在");
		}
	}

	/**
	 * 给区域绑定经理（指定经纪人）
	 * @param dbArea
	 * @param agentId 要绑定的经纪人ID
	 */
	private void areaBindAgent(AgArea dbArea, Long agentId){
		// 查询修改前区域经理
		List<AgAgentArea> dbAgentAreaList = agAgentAreaMapper.selectList(
				Wrappers.lambdaQuery(AgAgentArea.class)
						.eq(AgAgentArea::getAreaId, dbArea.getId())
						.eq(AgAgentArea::getAreaLev, dbArea.getAreaLev())
						.eq(AgAgentArea::getTitleType, AgAgentArea.TITLE_TYPE_MANAGE)
						.orderByAsc(AgAgentArea::getId));
		// 如果设置了新经理ID，则发送消息给新绑定的经理
		Long sendMsgToNewManage = null;
		// 如果设置了原经理ID，则发送消息给原绑定的经理
		Long sendMsgToOriginalManage = null;

		AgAgentArea saveBean = null;
		if (dbAgentAreaList.size() > 0){
			saveBean = dbAgentAreaList.get(0);
			Long oAgentId = saveBean.getAgentId();
			if (!oAgentId.equals(agentId)) {
				// 如果存在经理，并且经理ID不同则修改
				// 如果原经理激活此区域，取消绑定后需要发送消息
				AgAgentArea agentArea = getManageArea(oAgentId);
				if (saveBean.getAreaId().equals(agentArea.getAreaId())){
					sendMsgToOriginalManage = oAgentId;
				}
				if (agentId == null) {
					agAgentAreaMapper.deleteById(saveBean.getId());
				}else {
					// 如果新经理是首次绑定，成功绑定后需要发送消息
					boolean hasManage = hasManageArea(agentId);
					if (!hasManage) {
						sendMsgToNewManage = agentId;
					}
					saveBean.setAgentId(agentId);
					saveBean.setAreaActive(0);
					saveBean.setCreatedAt(new Date());
					agAgentAreaMapper.updateById(saveBean);
				}
			}
		}else {
			// 如果新经理是首次绑定，成功绑定后需要发送消息
			boolean hasManage = hasManageArea(agentId);
			if (!hasManage){
				sendMsgToNewManage = agentId;
			}
			saveBean = new AgAgentArea();
			saveBean.setAgentId(agentId);
			saveBean.setAreaId(dbArea.getId());
			saveBean.setAreaLev(dbArea.getAreaLev());
			saveBean.setTitleType(AgAgentArea.TITLE_TYPE_MANAGE);
			saveBean.setAreaActive(0);
			saveBean.setCreatedAt(new Date());
			agAgentAreaMapper.insert(saveBean);
		}
		if (sendMsgToNewManage != null) {
			sendMsgWhenManageChange(sendMsgToNewManage);
		}
		if (sendMsgToOriginalManage != null) {
			sendMsgWhenManageChange(sendMsgToOriginalManage);
		}
	}
	private void sendMsgWhenManageChange(Long agentId){
		try {
			AppNoticeUtil.sendSingleNotice(ConfigUtil.getString("ehp.domain.agentPush"), agentId, AppNoticeUtil.NoticeType.AG_CHANGE_AREA_MANAGE,
					new AppNoticeUtil.SimpleNotice("消息通知", "经理区域变更", System.currentTimeMillis()));
		}catch (Exception e){
			log.error("经理区域变更通知失败", e);
		}
	}

	/**
	 * 修改省区父id
	 * @param ids
	 * @param parentId
	 */
	private void updateAgAreaParentId(List<Long> ids, Long parentId){
		if (ids == null || ids.size() == 0){
			return;
		}
		this.lambdaUpdate()
				.set(AgArea::getParentId, parentId)
				.in(AgArea::getId, ids)
				.eq(AgArea::getAreaLev, AgArea.AREA_LEV_PROVINCE)
				.update();
	}

	@Override
	public List<IdAndName> findCanChangeCity(Long areaId) {
		List<AgArea> dbList = this.lambdaQuery()
				.eq(AgArea::getParentId, areaId)
				.or()
				.isNull(AgArea::getParentId)
				.list();
		return dbList.stream()
				.map(area -> IdAndName.of(area.getId(), area.getAreaName()))
				.collect(Collectors.toList());
	}

	@Override
	public List<IdAndName> findCityAll() {
		List<AgArea> dbList = this.lambdaQuery()
				.eq(AgArea::getAreaLev, AgArea.AREA_LEV_PROVINCE)
				.list();
		// 注意：这里要取省份名称
		return dbList.stream()
				.map(area -> IdAndName.of(area.getId(), area.getCityName()))
				.collect(Collectors.toList());
	}

	private QueryWrapper<AreaPagePO> buildEntityWrapper(PageParamsVO pageParamsVO, AreaPagePO pagePO) {

		QueryWrapper<AreaPagePO> entityWrapper = pageParamsVO.getEntityWrapper("t");
		if (pagePO == null){
			return entityWrapper;
		}
		Long areaId = null;
        if (StringUtils.isNotEmpty(pagePO.getId())) {
			if (NumberUtil.isNumber(pagePO.getId())){
				areaId = Long.valueOf(pagePO.getId());
			}else{
				areaId = -1L;
			}
		}
		entityWrapper.eq(areaId != null, "t.id", areaId);
		entityWrapper.like(StringUtils.isNotEmpty(pagePO.getAreaName()), "t.area_name", pagePO.getAreaName());
		entityWrapper.like(StringUtils.isNotEmpty(pagePO.getAgentName()), "agent.name", pagePO.getAgentName());
		entityWrapper.eq(StringUtils.isNotEmpty(pagePO.getAgentPhone()), "agent.phone", pagePO.getAgentPhone());
		return entityWrapper;
	}

	/**
	 * 查询经纪人是否包含经理角色
	 * @param agentId
	 * @return
	 */
	private boolean hasManageArea(Long agentId){
		long manageRowNum = agAgentAreaMapper.selectCount(Wrappers.lambdaQuery(AgAgentArea.class)
				.eq(AgAgentArea::getAgentId, agentId).eq(AgAgentArea::getTitleType, AgAgentArea.TITLE_TYPE_MANAGE));
		return manageRowNum > 0;
	}

	/**
	 * 查询当前激活的管理区域
	 * @param agentId
	 * @return
	 */
	private AgAgentArea getManageArea(Long agentId){
		List<AgAgentArea> dbList = agAgentAreaMapper.selectList(Wrappers.lambdaQuery(AgAgentArea.class)
				.eq(AgAgentArea::getAgentId, agentId).eq(AgAgentArea::getTitleType, AgAgentArea.TITLE_TYPE_MANAGE).orderByAsc(AgAgentArea::getId));
		AgAgentArea activeItem = null;
		if (dbList.size() > 0) {
			for (AgAgentArea agentArea : dbList) {
				if (agentArea.getAreaActive() != null && agentArea.getAreaActive() == AgAgentArea.AREA_ACTIVE_YSE) {
					activeItem = agentArea;
				}
			}
			if (activeItem == null && dbList.size() > 0) {
				activeItem = dbList.get(0);
			}
		}
		return activeItem;
	}
}
